local json = require("quick.json")

local socket = require "socket"

local HttpProtocol = "https://"

local HttpNetwork = {}

local UseHttpDNS = Config.useHttpDNS

local DefaultConnectTimeout = 15

cc(HttpNetwork):addComponent("components.behavior.EventProtocol"):exportMethods()

HttpNetwork.requestCount = 0 

-- httpdns解析后的ip
HttpNetwork.httpDNSURLCache = nil

local errorCodeDict = {
    [-1] = L10N.getString("network_loadingFailed"),
    [300] = L10N.getString("network_downloadResourceAgain"),
    [400] = L10N.getString("network_requestResourceFailed"),
    [404] = L10N.getString("network_cannotFindResource"),
    [500] = L10N.getString("network_errServerInside"),
    [502] = L10N.getString("network_ServerMaintain")
}

if cc.SetTimeoutForHttpConnect then
    cc.SetTimeoutForHttpConnect(DefaultConnectTimeout)
end

if cc.SetTimeoutForHttpRead then
    cc.SetTimeoutForHttpRead(DefaultConnectTimeout)
end

function HttpNetwork.joinUrl(host,port,path)
    if port then
        return HttpProtocol..host..":"..port.."/"..(path or "")
    else
        return HttpProtocol..host.."/"..(path or "")
    end
end

function HttpNetwork.queryIP(url,cb,block)
    local protocol,domain,port,dir = string.parseUrl(url)
    local isIPV4 = string.matchIPV4(domain)
    -- 接入腾讯的httpdns
    if not isIPV4 and UseHttpDNS then
        app.channelAPI:getHostByNameAsync(domain, function(ipAry)
            if ipAry then
                dump(ipAry, "httpdns CallbackipAry")               
                local ipv4 = ipAry[1] or "0"
                local ipv6 = ipAry[2] or "0"
                if ipv6 ~= "0" then
                    local ipv6Url = HttpNetwork.getNewUrl(protocol, "["..ipv6.."]", port, dir)
                    local ipv4Url = HttpNetwork.getNewUrl(protocol, ipv4, port, dir)
                    HttpNetwork.httpDNSURLCache = {ipv4Url, ipv6Url}
                    dump(HttpNetwork.httpDNSURLCache, "httpdns urlCache")
                    cb(ipv6Url)
                elseif ipv4 ~= "0" then
                    local ipv4Url = HttpNetwork.getNewUrl(protocol, ipv4, port, dir)
                    print("httpdns ipv4Url--------->>>>"..ipv4Url)
                    cb(ipv4Url)
                else
                    cb(url)
                end
            else
                cb(url)
            end
        end)
    else
        cb(url)
    end
    -- ios 不使用HttpDNS
    -- if not isIPV4 and UseHttpDNS and not app:isIOS() then
    --     local apiUrl = string.format("http://119.29.29.29/d?dn=%s.&ip=1.1.1.1",domain)
    --     HttpNetwork._request(apiUrl,function(response,errorText,code)
    --         local ip = response or ""
    --         if code==200 and string.matchIPV4(ip) then
    --             local newUrl = protocol.."://"..ip
    --             if string.len(port)>0 then
    --                 newUrl = newUrl..":"..port
    --             end
    --             newUrl=newUrl..dir
    --             cb(newUrl)
    --         else
    --             cb(url)
    --         end
    --     end,"GET",cc.XMLHTTPREQUEST_RESPONSE_STRING,block)
    -- else
    --     cb(url)
    -- end
end

function HttpNetwork.request(url,listener,method,responseType,block,data)
    -- 长连接不使用dns解析，服务器可能根据域名做逻辑
    -- HttpNetwork.queryIP(url,function(newUrl) 
    --     HttpNetwork._request(newUrl,listener,method,responseType,block,data)
    -- end,block)
    HttpNetwork._request(url,listener,method,responseType,block,data)
end

function HttpNetwork._request(url,listener,method,responseType,block,data)
     print("======>Http send url = ",url)
    local xhr = cc.XMLHttpRequest:new()
    xhr.responseType = responseType
    xhr.beginTime = socket.gettime()
    xhr:open(method, url)

    local function onReadyStateChanged(sender)
        local sender = type(sender)~="userdata" and xhr or sender
        local response = ""
        local code = sender.status
        local errorText = nil

        -- 如果是ipv6连接失败，而ipv4存在，则再尝试用ipv4连接
        local isNeedRetry = false
        if code ~= 200 and HttpNetwork.httpDNSURLCache and
            HttpNetwork.httpDNSURLCache[2] == url and
            HttpNetwork.httpDNSURLCache[1] and HttpNetwork.httpDNSURLCache[1] ~= "0" then
                isNeedRetry = true
        end

        if code == 200 then
            response = sender.response
            HttpNetwork.httpDNSURLCache = nil
        elseif not isNeedRetry then
            errorText = HttpNetwork.getErrorMessage(code,sender.statusText) 
            
            EM:notify("OnNetworkStatusChange", Enums.NetworkStatusAdEvent.HttpConnFail)
        end

        release_print("====>Http ",url,"code:",code,"state:",sender.readyState,"statustext:",sender.statusText, "response:",response)
        
        if block then
            HttpNetwork.requestCount = HttpNetwork.requestCount - 1
        end

        if isNeedRetry then
            print("httpdns urlCache-------->>>>"..HttpNetwork.httpDNSURLCache[1])
            HttpNetwork._request(HttpNetwork.httpDNSURLCache[1], listener, method, responseType, block, data)
            HttpNetwork.httpDNSURLCache = nil
        else
            if listener then
                if responseType==cc.XMLHTTPREQUEST_RESPONSE_JSON then
                    response = json.decode(response)
                    if code == 200 and type(response) ~= "table" then
                        errorText = L("network_errResource")
                    end
                end
                listener(response,errorText,code)
            end
    
            sender:unregisterScriptHandler()
        end
    end

    xhr:registerScriptHandler(onReadyStateChanged)
    if data then
        xhr:send(data)
    else
        xhr:send()
    end

    if block then
        HttpNetwork.requestCount = HttpNetwork.requestCount + 1
    end
end

function HttpNetwork.reqJsonData(url,listener,method,block,data,ignoreDNS)
    if ignoreDNS then
        HttpNetwork._request(url,listener,method,cc.XMLHTTPREQUEST_RESPONSE_JSON,block,data)
    else
        HttpNetwork.request(url,listener,method,cc.XMLHTTPREQUEST_RESPONSE_JSON,block,data)
    end
end

function HttpNetwork.reqRawData(url,listener,method,block,data,ignoreDNS)
    if ignoreDNS then
        HttpNetwork._request(url,listener,method,cc.XMLHTTPREQUEST_RESPONSE_STRING,block,data)
    else
        HttpNetwork.request(url,listener,method,cc.XMLHTTPREQUEST_RESPONSE_STRING,block,data)
    end
end


function HttpNetwork.getErrorMessage(errorCode,default)
    local msg = nil
    if not network.isInternetConnectionAvailable() then
        msg = L("lua_code_text_436")
    else
        msg = errorCodeDict[errorCode]
        if not msg then
            local code = math.floor(errorCode/100) * 100
            msg = errorCodeDict[code]
        end
        if not msg then
            msg = L("network_error")
        end
        msg = string.format("%s(%s)", msg, errorCode)
    end
    return msg
end


function HttpNetwork.isConnecting()
    return HttpNetwork.requestCount > 0 
end

function HttpNetwork.getNewUrl(protocol, domain, port, dir)
    local httpdnsUrl
    if domain and domain ~= "0" then
        httpdnsUrl = protocol.."://"..domain
        if string.len(port)>0 then
            httpdnsUrl = httpdnsUrl..":"..port
        end
        httpdnsUrl = httpdnsUrl..dir
    end
    return httpdnsUrl
end

return HttpNetwork